<?php
/**
 * @license http://www.gnu.org/licenses/gpl.html GNU GPL, version 3 or later
 * @package FrontPress
 * @subpackage Install
 */

/**
 * Base installer class. Before any given page loads, .
 *
 * @since 2010-08-01-r42
 * @version $Id: class.fp-installer.php 50 2010-08-03 20:34:20Z Nightgunner5 $
 */
abstract class FP_Installer {
	/**
	 * @var BPDB
	 */
	var $db;
	/**
	 * @var int
	 */
	var $step = 1;

	/**
	 * @var string
	 */
	var $config_prefix = '';
	/**
	 * @var string
	 */
	var $config_filename = 'config.php';

	/**
	 * @var int
	 */
	var $db_version = 0;

	function __construct( &$db ) {
		$this->db =& $db;

		$base_path = parse_url( frontpress_uri(), PHP_URL_PATH );
		$path = preg_replace( '@^' . untrailingslashit( $base_path ) . '([^\?]+)(\?.*)?$@', '$1', $_SERVER['REQUEST_URI'] );
		if ( $path == '/install/step-2' ) {
			$this->step = 2;

			if ( strtoupper( $_SERVER['REQUEST_METHOD'] ) == 'POST' ) {
				$this->parse_db_credentials();
			}
		}
		if ( $db ) {
			$this->step = 3;
		}

		if ( $this->need_to_install() )
			$this->run();
	}

	function run() {
		frontpress_title( sprintf( __( 'Install Step %d' ), $this->step ) );
		frontpress_breadcrumb( __( 'Install' ), sprintf( _x( 'Step %d', 'installer' ), $this->step ) );
		frontpress_tmpl_header( array( 'suppress_log_in_link' => true ) );

		call_user_func( array( &$this, 'step_' . $this->step ) );

		frontpress_tmpl_footer();
		exit;
	}

	function need_to_install() {
		if ( !$this->db )
			return true;

		if ( backpress_get_option( 'db_version' ) == $this->db_version )
			return false;

		$schemas = $this->get_schemas();

		foreach ( array_keys( $schemas ) as $table ) {
			$schemas[$table] = sprintf( $schemas[$table], $this->db->$table );
		}

		$need_to_install = array_filter( BP_SQL_Schema_Parser::delta( $this->db, $schemas, false, false ) );

		if ( $need_to_install )
			return true;

		backpress_update_option( 'db_version', $this->db_version );
		return false;
	}

	function parse_db_credentials() {
		$name = $_POST['db_name'];
		$user = $_POST['db_user'];
		$password = $_POST['db_pass'];
		$host = $_POST['db_host'];
		$prefix = $_POST['db_prefix'];

		if ( !$name || !$user || !$password || !$host || !$prefix ) {
			FP_Notice::add( __( 'All fields are required.' ), 'error' );
			header( 'Location: ' . frontpress_uri_current() );
			exit;
		}
		$db = new BPDB_Multi( compact( 'name', 'user', 'password', 'host' ) + array(
			'errors' => 'suppress'
		) );
		if ( is_wp_error( $error = $db->error ) ) {
			FP_Notice::add( $error->get_error_message(), 'error' );
			header( 'Location: ' . frontpress_uri_current() );
			exit;
		}
		if ( is_wp_error( $error = $db->set_prefix(  $prefix ) ) ) {
			FP_Notice::add( $error->get_error_message(), 'error' );
			header( 'Location: ' . frontpress_uri_current() );
			exit;
		}

		$fp = fopen( dirname( $_SERVER['SCRIPT_FILENAME'] ) . '/' . $this->config_filename, 'w' );

		fwrite( $fp, "<?php\n" );
		fwrite( $fp, "\n" );
		fwrite( $fp, "define( '{$this->config_prefix}DB_USER',     " . var_export( $user, true ) . " );\n" );
		fwrite( $fp, "define( '{$this->config_prefix}DB_PASSWORD', " . var_export( $password, true ) . " );\n" );
		fwrite( $fp, "define( '{$this->config_prefix}DB_NAME',     " . var_export( $name, true ) . " );\n" );
		fwrite( $fp, "define( '{$this->config_prefix}DB_HOST',     " . var_export( $host, true ) . " );\n" );
		fwrite( $fp, "define( '{$this->config_prefix}DB_PREFIX',   " . var_export( $prefix, true ) . " );\n" );

		fclose( $fp );

		FP_Notice::add( __( 'Wrote config file.' ), 'success' );
		header( 'Location: ' . frontpress_uri( '/install/step-3' ) );
		exit;
	}

	/**
	 * Install step 1 is usually used to describe the installation process.
	 */
	abstract function step_1();

	/**
	 * Install step 2 is usually used to ask for database credentials.
	 */
	abstract function step_2();

	abstract function step_3();

	function install() {
		$schemas = $this->get_schemas();

		foreach ( array_keys( $schemas ) as $table ) {
			$schemas[$table] = sprintf( $schemas[$table], $this->db->$table );
		}

		$this->db->hide_errors();
		$result = BP_SQL_Schema_Parser::delta( $this->db, $schemas );

		echo '<strong>', __( 'Messages' ), '</strong><br/><textarea style="width: 99%; height: 10em;" disabled="disabled">' . esc_html( implode( "\n", $result['messages'] ) ) . '</textarea>';
		echo '<br/><br/>';
		echo '<strong>', __( 'Errors' ), '</strong><br/><textarea style="width: 99%; height: 10em; color: #f00;" disabled="disabled">' . esc_html( implode( "\n", $result['errors'] ) ) . '</textarea>';

		FP_Thing::$db =& $this->db;
		if ( !FP_User::all_with_limit( 1 ) ) {
			$password = WP_Pass::generate_password();
			$user = new FP_User( array(
				'user_login'      => 'admin',
				'user_nicename'   => 'admin',
				'user_email'      => 'admin@example.com',
				'user_url'        => '',
				'user_status'     => 0,
				'user_registered' => date( 'Y-m-d H:i:s' ),
				'user_pass'       => WP_Pass::hash_password( $password ),
				'display_name'    => 'admin'
			) );
			$user->save();

			// Get the user objects initialized.
			FP_User::current();

			$_user = new BP_User( FP_User::all_with_limit( 1 )->ID );
			$_user->add_role( 'admin' );

			printf( __( 'You can now log in with the username <code>%s</code> and the password <code>%s</code>.' ), esc_html( $user->user_login ), esc_html( $password ) );
		}
	}

	abstract function get_schemas();

	function get_user_schema() {
		return array(
			'users' => "CREATE TABLE %s (
				ID bigint(20) unsigned NOT NULL auto_increment,
				user_login varchar(60) NOT NULL default '',
				user_pass varchar(64) NOT NULL default '',
				user_nicename varchar(50) NOT NULL default '',
				user_email varchar(100) NOT NULL default '',
				user_url varchar(100) NOT NULL default '',
				user_registered datetime NOT NULL default '0000-00-00 00:00:00',
				user_activation_key varchar(60) NOT NULL default '',
				user_status int(11) NOT NULL default '0',
				display_name varchar(250) NOT NULL default '',
				PRIMARY KEY  (ID),
				KEY user_login_key (user_login),
				KEY user_nicename (user_nicename)
			)",

			'usermeta' => "CREATE TABLE %s (
				umeta_id bigint(20) NOT NULL auto_increment,
				user_id bigint(20) NOT NULL default '0',
				meta_key varchar(255) default NULL,
				meta_value longtext,
				PRIMARY KEY  (umeta_id),
				KEY user_id (user_id),
				KEY meta_key (meta_key)
			)"
		);
	}

	function get_meta_schema() {
		return array(
			'meta' => "CREATE TABLE `%s` (
				`meta_id` bigint(20) NOT NULL AUTO_INCREMENT,
				`object_type` varchar(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'my_option',
				`object_id` bigint(20) NOT NULL DEFAULT '0',
				`meta_key` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
				`meta_value` longtext COLLATE utf8_unicode_ci,
				PRIMARY KEY (`meta_id`),
				KEY `object_type__meta_key` (`object_type`,`meta_key`),
				UNIQUE KEY `object_type__object_id__meta_key` (`object_type`,`object_id`,`meta_key`)
			)"
		);
	}
}
